package com.derekandbritt.booST;

import java.util.Date;

import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.derekandbritt.booST.data.Challenge;
import com.derekandbritt.booST.exceptions.ConnectionException;
import com.derekandbritt.booST.exceptions.DataFormatException;

public class ActiveChallenge extends booSTActivity {

	public final static String CHALLENGE_KEY = "com.derekandbritt.booST.challenge";

	private Challenge challenge;
	private String userId;
	
	private boolean isServiceBound = false;
    private ChallengeService challengeService;
    private ServiceConnection mConnection;
    
    private AlertDialog.Builder quitterAlert;
    
	private final Handler handler = new Handler();
	private final Runnable initializeService = new Runnable() {
        public void run() {
            if(challengeService == null)
                handler.postDelayed(initializeService, 100);
            else {
                challengeService.start(challenge);
                updateUI();
            }
        }
	};
    private final Runnable updateUI = new Runnable() {
		   public void run() {
			   updateUI();
		   }
    };
    
	public void displayContent() throws ConnectionException, DataFormatException {
		
		this.setContentView(R.layout.activity);
    	
		long challengeId = this.getIntent().getExtras().getLong(CHALLENGE_KEY);
		challenge = booSTEndpoint.getChallenge(challengeId);
		
		displayChallenge();
		
		if(challenge.getType() == Challenge.Type.COMPETITIVE) {
			// hide time remaining from the view
			findViewById(R.id.TimeRemainingLayout).setVisibility(View.GONE);
		}
		else if(challenge.getType() == Challenge.Type.COOPERATIVE) {			
			// hide time elapsed from the view
			findViewById(R.id.TimeElapsedLayout).setVisibility(View.GONE);
		}
		
		mConnection = new ServiceConnection() {
	        public void onServiceConnected(ComponentName className, IBinder service) {
	            // This is called when the connection with the service has been
	            // established, giving us the service object we can use to
	            // interact with the service.  Because we have bound to a explicit
	            // service that we know is running in our own process, we can
	            // cast its IBinder to a concrete class and directly access it.
	            challengeService = ((ChallengeService.LocalBinder)service).getService();
	        }

	        public void onServiceDisconnected(ComponentName className) {
	            // This is called when the connection with the service has been
	            // unexpectedly disconnected -- that is, its process crashed.
	            // Because it is running in our same process, we should never
	            // see this happen.
	            challengeService = null;
	        }
	    };
		
        // Establish a connection with the service.  We use an explicit
        // class name because we want a specific service implementation that
        // we know will be running in our own process (and thus won't be
        // supporting component replacement by other applications).
		if(!isServiceBound) {
		    Intent intent = new Intent(this, ChallengeService.class);
		    //intent.putExtra(ChallengeService.CHALLENGE_TYPE_KEY, challenge.getType().name());
		    //intent.putExtra(ChallengeService.CHALLENGE_TIME_LIMIT_KEY, challenge.getTimeLimit());
		    //intent.putExtra(ChallengeService.CHALLENGE_DISTANCE_KEY, challenge.getDistance());
		    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
		    isServiceBound = true;
		    booSTActivity.activeChallengeId = challengeId;
		}
		
		setupQuitChallengeButton();
		
		handler.removeCallbacks(initializeService);
		handler.removeCallbacks(updateUI);
		handler.post(initializeService);
	}

	private void displayChallenge() throws ConnectionException, DataFormatException {
		
    	userId = booSTEndpoint.getUser().userID;
		    	
		String friendId;
    	if(challenge.getSender().equals(userId))
    		friendId = challenge.getReceiver();
    	else
    		friendId = challenge.getSender();
		
		configureChallengeDetails(challenge, friendId);
	}
	
    private void updateUI() {
        
        if(challengeService == null) {
            handler.postDelayed(updateUI, 1000);
            return;
        }
        
        if(challengeService.isChallengeComplete())
            completeChallenge((int)challengeService.getTimeElapsed());
        
        updateDistanceValues();
        
        if(challenge.getType() == Challenge.Type.COMPETITIVE) {
            updateTimeElapsed();
        }
        else if(challenge.getType() == Challenge.Type.COOPERATIVE) {
            updateTimeRemaining();
        }
        
        handler.postDelayed(updateUI, 1000);
    }	
	
	private void updateTimeElapsed() {
        final TextView timeElapsedView = (TextView)findViewById(R.id.TimeElapsed);

        long timeElapsed = challengeService.getTimeElapsed();
        long minutes = timeElapsed / 60000;
        long seconds = (timeElapsed % 60000) / 1000;
        
        String minutesText = (minutes < 10 ? "0" + minutes  : "" + minutes);
        String secondsText = (seconds < 10 ? "0" + seconds  : "" + seconds);
        timeElapsedView.setText(minutesText + ":" + secondsText);
    }
	
	private void updateTimeRemaining() {
	    final TextView timeRemaining = (TextView)findViewById(R.id.TimeRemaining);
    
	    long millisUntilFinished = challengeService.getTimeRemaining();
	    long minutes = millisUntilFinished / 60000;
	    long seconds = (millisUntilFinished % 60000) / 1000;
    
	    String minutesText = (minutes < 10 ? "0" + minutes  : "" + minutes);
	    String secondsText = (seconds < 10 ? "0" + seconds  : "" + seconds);
        timeRemaining.setText(minutesText + ":" + secondsText);
	}
	
	private void updateDistanceValues() {
		
	    long feetCovered = challengeService.getFeetCovered();
		double miles = ((double)feetCovered) / 5280;
		double milesRemaining = challenge.getDistance() - miles;
		
		TextView distanceCovered = (TextView)findViewById(R.id.DistanceCovered);
		TextView distanceRemaining = (TextView)findViewById(R.id.DistanceRemaining);
		
		if(milesRemaining <= 0) {
			distanceCovered.setText(decimalFormatter.format(challenge.getDistance()) + " miles");
			distanceRemaining.setText("0.00 miles");
		} else {
			distanceCovered.setText(decimalFormatter.format(miles) + " miles");
			distanceRemaining.setText(decimalFormatter.format(milesRemaining) + " miles");
		}
	}
	
	private void setupQuitChallengeButton() {
	    
	    quitterAlert = new AlertDialog.Builder(ActiveChallenge.this)
            .setTitle("Confirmation")
            .setMessage("Are you sure that you want to quit?")
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    completeChallenge(-1);
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) { }
            });
	    
		Button quitButton = (Button)findViewById(R.id.QuitChallengeButton);
		quitButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) { quitterAlert.show(); }
		});
	}
	
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
        if (keyCode == KeyEvent.KEYCODE_BACK) { 
            quitterAlert.show();
            return true;
        } else 
            return super.onKeyDown(keyCode, event); 
    } 
	
	private void completeChallenge(int timeElapsed) {

	    // allow other activities to be displayed
	    booSTActivity.activeChallengeId = -1;
	    
	    // stop updating the UI thread
	    handler.removeCallbacks(updateUI);
	    
        if (isServiceBound) {
            // Detach our existing connection.
            unbindService(mConnection);
            isServiceBound = false;
        }
	    
		// get a new current copy of the challenge from the server
		// TODO implement locking so challenges cannot be overwritten
		try {
			Challenge currentChallenge = booSTEndpoint.getChallenge(challenge.getId());
			challenge = currentChallenge;
		} catch(Exception e) {
			handleError(e);
		}
		
		//TODO if the challenge has been terminated by the other party then
		// display the appropriate message.
		
		// compute the new state of the challenge
		if(challenge.getSender().equals(userId)) 
			challenge.setSenderTime(timeElapsed);
		else
			challenge.setReceiverTime(timeElapsed);
		
		if(challenge.getSenderTime() != 0 && challenge.getReceiverTime() != 0)
			challenge.setStatus(Challenge.Status.COMPLETED);
		
		challenge.setLastUpdated(new Date(System.currentTimeMillis()));
		
		try {
		    // set the challenge and close the activity when done
			setChallenge(challenge, true);
			displayChallenge();
		} catch (DataFormatException e) {
			handleError(e);
		} catch (ConnectionException e) {
			handleError(e);
		}
	}
}
